package com.wangyb.wework.service.contact;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.core.page.PagePlus;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.utils.PageUtils;
import com.wangyb.wework.bo.WwTagAddBo;
import com.wangyb.wework.bo.WwTagEditBo;
import com.wangyb.wework.bo.WwTagQueryBo;
import com.wangyb.wework.entity.contact.WwTag;
import com.wangyb.wework.entity.contact.WwTagGroup;
import com.wangyb.wework.entity.contact.WwContactTagPivot;
import com.wangyb.wework.mapper.contact.WwTagMapper;
import com.wangyb.wework.utils.WxApiUtils;
import com.wangyb.wework.vo.WwTagVo;
import com.wangyb.wework.wxApi.CorpTagListResp;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 客户标签Service业务层处理
 *
 * @Author: wangyb
 * @Date: 2021/6/30 10:49 下午
 */
@Service
public class WwTagServiceImpl extends ServiceImpl<WwTagMapper, WwTag> implements IWwTagService {
	@Autowired
	private IWwTagGroupService iWwTagGroupService;
	@Autowired
	private IWwTagService iWwTagService;
	@Autowired
	private IWwContactTagPivotService iWwContactTagPivotService;

	@Override
	@Transactional
	public void syncContactTag(Long corpId){
		CorpTagListResp resp = WxApiUtils.getTagDetail(corpId, null);
		List<WwTagGroup> remoteTagGroupList = resp.getTagGroupList();
		remoteTagGroupList.forEach(g->{g.setCorpId(corpId);});
		Set<String> remoteGroupIdSet = remoteTagGroupList.stream().map(g -> g.getWxGroupId()).collect(Collectors.toSet());

		//本地数据库已存在的taggroup
		List<WwTagGroup> localTagGroupList = iWwTagGroupService
			.lambdaQuery()
			.eq(WwTagGroup::getCorpId, corpId)
			.list();
		Set<String> localGroupIdSet = localTagGroupList.stream().map(g -> g.getWxGroupId()).collect(Collectors.toSet());
		Map<String, WwTagGroup> localGroupMap = localTagGroupList.stream().collect(Collectors.toMap(WwTagGroup::getWxGroupId, Function.identity()));

		//同步数据分为三种情况,新增，删除，更新
		//1.新增标签组，当本地无而远端有时，新增该标签组
		remoteTagGroupList.stream()
			.filter(g -> !localGroupIdSet.contains(g.getWxGroupId()))
			.forEach(g->{
				//新增标签组
				g.setCorpId(corpId);
				iWwTagGroupService.save(g);
				//新增标签
				g.getTagList().forEach(t->{
					t.setTagGroupId(g.getId());
					t.setCorpId(corpId);
				});
				iWwTagService.saveBatch(g.getTagList());
			});
		//2.删除标签组,当本地有该标签组而远端没有时
		// 即删除标签组、其下的所有标签、这些标签与客户的关联关系
		localTagGroupList.stream()
			.filter(g->!remoteGroupIdSet.contains(g.getWxGroupId()))
			.forEach(g->{
				Set<Long> localTagIdSet = lambdaQuery()
					.select(WwTag::getId)
					.eq(WwTag::getCorpId, corpId)
					.eq(WwTag::getTagGroupId, g.getId())
					.list()
					.stream().map(WwTag::getId)
					.collect(Collectors.toSet());
				if (localTagIdSet.size()>0){
					//删除客户-标签关联对象
					iWwContactTagPivotService.getBaseMapper()
						.delete(
							new LambdaQueryWrapper<WwContactTagPivot>()
								.in(WwContactTagPivot::getTagId,localTagIdSet));
					//删除标签对象
					iWwTagService.removeByIds(localTagIdSet);
				}
				//删除标签组
				iWwTagGroupService.removeById(g.getId());
			});
		//3.更新标签组，当本地有，远端也有该标签组时
		remoteTagGroupList.stream()
			.filter(g->localGroupIdSet.contains(g.getWxGroupId()))
			.forEach(g->{
				//3.1更新标签组
				WwTagGroup localGroup = localGroupMap.get(g.getWxGroupId());
				g.setId(localGroup.getId());
				iWwTagGroupService.updateById(g);
				//3.2新增标签，更新标签，删除标签，
				List<WwTag> localTagList = this.lambdaQuery()
					.eq(WwTag::getCorpId, corpId)
					.eq(WwTag::getTagGroupId, g.getId())
					.list();
				Map<String, WwTag> localTagMap = localTagList.stream().collect(Collectors.toMap(WwTag::getWxTagId, Function.identity()));

				List<WwTag> remoteTagList = g.getTagList();
				Map<String, WwTag> remoteTagMap = remoteTagList.stream().collect(Collectors.toMap(WwTag::getWxTagId, Function.identity()));

				//3.2.1 新增标签，即不在本地的所有标签
				List<WwTag> newTagList = remoteTagList.stream()
					.filter(rt -> !localTagMap.containsKey(rt.getWxTagId()))
					.collect(Collectors.toList());
				newTagList.forEach(nt->nt.setCorpId(corpId));
				this.saveBatch(newTagList);
				//3.2.2 删除标签，即删除在本地有而远端没有的所有标签及其对应的客户关联关系
				Set<Long> deleteTagIdSet = localTagList.stream()
					.filter(lt -> !remoteTagMap.containsKey(lt.getWxTagId()))
					.map(t -> t.getId())
					.collect(Collectors.toSet());
				if (deleteTagIdSet.size()>0){
					//删除客户-标签关联对象
					iWwContactTagPivotService.getBaseMapper()
						.delete(
							new LambdaQueryWrapper<WwContactTagPivot>()
								.in(WwContactTagPivot::getTagId,deleteTagIdSet));
					//删除标签对象
					this.removeByIds(deleteTagIdSet);
				}

				//3.2.3 更新标签，即更新 在本地有，远端也有的标签，用远端信息更新本地信息
				remoteTagList.stream()
					.filter(rt->localTagMap.containsKey(rt.getWxTagId()))
					.forEach(rt->{
						WwTag localTag = localTagMap.get(rt.getWxTagId());
						rt.setId(localTag.getId());
						rt.setCorpId(corpId);
						this.updateById(rt);
					});
			});
	}

	/**
	 * 根据corpId 查询wxContactId与Id的对应关系
	 * @param corpId
	 * @return
	 */
	@Override
	public Map<String, Long> getContactTagByCorId(Long corpId) {
		return this.lambdaQuery()
			.select(WwTag::getWxTagId, WwTag::getId)
			.eq(WwTag::getCorpId,corpId)
			.list()
			.stream()
			.collect(Collectors.toMap(WwTag::getWxTagId, WwTag::getId));
	}
	@Override
	public List<WwTagGroup> getTagWithUsedNum(Long corpId){
		List<WwTagGroup> groupList = iWwTagGroupService.lambdaQuery().eq(WwTagGroup::getCorpId, corpId).list();

		List<WwTag> tagList = this.lambdaQuery().eq(WwTag::getCorpId, corpId).list();

		//取出tagId 的对应数量
		if (tagList.size()>0){
			Set<Long> tagIdSet = tagList.stream().map(t -> t.getId()).collect(Collectors.toSet());
			QueryWrapper<WwContactTagPivot> queryWrapper = new QueryWrapper<>();
			queryWrapper.select("tag_id tagId,count(1) count")
				.lambda()
				.eq(WwContactTagPivot::getCorpId,corpId)
				.in(WwContactTagPivot::getTagId,tagIdSet)
				.groupBy(WwContactTagPivot::getTagId);
			List<Map<String, Object>> tagCntMapList = this.iWwContactTagPivotService.listMaps(queryWrapper);
			Map<Object, Long> tagCntMap = tagCntMapList.stream().collect(Collectors.toMap(m ->m.get("tagId"),m->Long.valueOf(m.get("count").toString())));

			//取出该标签的对应数量
			tagList.forEach(t->t.setNums(tagCntMap.getOrDefault(t.getId(),0L)));
//			tagList.forEach(t->t.setNums(99));
		}


		groupList.forEach(g->{
			List<WwTag> subTagList = tagList.stream()
				.filter(t -> g.getId().equals(t.getTagGroupId()))
				.collect(Collectors.toList());
			g.setTagList(subTagList);
		});
		return groupList;
	}
	@Override
	public TableDataInfo<WwTagVo> queryPageList(WwTagQueryBo bo) {
		PagePlus<WwTag, WwTagVo> result = pageVo(PageUtils.buildPagePlus(), buildQueryWrapper(bo), WwTagVo.class);
		return PageUtils.buildDataInfo(result);
	}
	private LambdaQueryWrapper<WwTag> buildQueryWrapper(WwTagQueryBo bo) {
		Map<String, Object> params = bo.getParams();
		LambdaQueryWrapper<WwTag> lqw = Wrappers.lambdaQuery();
		return lqw;
	}
	@Override
	public List<WwTagVo> queryList(WwTagQueryBo bo) {
		return listVo(buildQueryWrapper(bo), WwTagVo.class);
	}

	@Override
	public WwTagVo queryById(Long id){
		return getVoById(id, WwTagVo.class);
	}
	@Override
	public Boolean insertByAddBo(WwTagAddBo bo) {
		WwTag add = BeanUtil.toBean(bo, WwTag.class);
		validEntityBeforeSave(add);
		return save(add);
	}
	/**
	 * 保存前的数据校验
	 *
	 * @param entity 实体类数据
	 */
	private void validEntityBeforeSave(WwTag entity){
		//TODO 做一些数据校验,如唯一约束
	}
	@Override
	public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
		if(isValid){
			//TODO 做一些业务上的校验,判断是否需要校验
		}
		return removeByIds(ids);
	}
	@Override
	public Boolean updateByEditBo(WwTagEditBo bo) {
		WwTag update = BeanUtil.toBean(bo, WwTag.class);
		validEntityBeforeSave(update);
		return updateById(update);
	}



}
